40장. WAF — 엣지에서 걸러내는 보안
이 장에서 말하고자 하는 것
CloudFront까지 깔면 사용자가 들어오는 길은 정리된다.
그런데 그 길에는 다음이 섞여 들어온다.
- SQL 인젝션 시도
- XSS 시도
- 크롤러
- 무차별 로그인 시도
- 봇
이걸 애플리케이션 직전에서 미리 걸러내는 도구가
AWS WAF (Web Application Firewall)
다.
CloudFront · ALB · API Gateway 같은 엣지/입구 단계에
WAF를 끼워 둔다.
1. WAF가 막는 것
WAF는 HTTP 요청을 검사해 다음을 막는다.
- OWASP Top 10에 가까운 공격 (SQLi, XSS, 경로 탐색 등)
- 알려진 악성 IP/봇
- 비정상적으로 잦은 요청 (Brute force)
- 지정한 국가/IP 차단
- 사용자 정의 패턴
2. WAF가 못 막는 것
WAF가 만능은 아니다.
- 비즈니스 로직 취약점 (권한 우회, 잘못된 상태 전이)
- 정상으로 보이는 정교한 봇
- 인증 후 발생하는 내부 권한 문제
WAF는 첫 번째 그물이지 마지막 방어선이 아니다
애플리케이션 단계의 검증을 대체하지 않는다
3. WAF의 구성 요소
Web ACL
WAF의 최상위 단위.
하나의 보호 묶음이다.
Web ACL
├─ Rule 1
├─ Rule 2
└─ Default action (allow / block)
Rule
요청이 어떤 패턴이면 어떻게 할지의 정의.
- 매칭 조건: 헤더 / 쿼리 / 바디 / IP 등
- 동작: ALLOW / BLOCK / COUNT / CAPTCHA
Rule Group
여러 룰을 묶은 단위.
직접 만들 수도 있고 AWS가 만들어 제공하는 것도 있다.
4. AWS Managed Rules — 가장 먼저 켜야 할 것
AWS가 제공하는 룰 묶음이다.
| 룰 그룹 | 내용 |
|---|---|
| Core rule set | OWASP 기반 일반 보호 |
| Known bad inputs | 알려진 악성 입력 |
| SQL database | SQL 인젝션 |
| Linux / Unix | 명령 주입 |
| Bot Control | 봇 탐지 |
| Anonymous IP list | VPN / Tor / 호스팅 IP |
WAF를 처음 켤 때는 우선 Core + Known bad inputs + SQL 부터
5. Rate-based Rule — 폭증 차단
같은 IP에서 짧은 시간에 너무 많이 들어오는 요청을 막는다.
5분 동안 같은 IP가 2,000회 초과 → BLOCK
로그인 페이지, 비밀번호 재설정, 인증 코드 검증처럼
악용되기 쉬운 엔드포인트에 따로 더 엄격한 임계를 건다.
6. Count 모드 — 일단 보기만 하기
새 룰을 켤 때 곧장 BLOCK 으로 두면
정상 트래픽까지 막아 사고가 난다.
WAF는 룰을 COUNT 모드로 둘 수 있다.
COUNT → 매칭은 잡지만 차단은 안 함
로그를 며칠 보고 오탐이 없는 걸 확인한 뒤
BLOCK으로 전환하는 게 운영의 표준 흐름이다.
7. WAF는 어디에 다는가
WAF는 다음 리소스에 붙는다.
- CloudFront
- ALB
- API Gateway
- Cognito User Pool
- AppSync
사용자 → [WAF + CloudFront] → ALB → ECS
CloudFront에 다는 게 가장 흔하다.
공격 트래픽이 origin까지 도달하기 전에 막는다.
가장 바깥에 한 번, 필요하면 ALB에도 추가로
8. 우리 서비스에서
척추 그림에서 WAF 위치다.
[사용자]
↓
[WAF + CloudFront] ← 여기, 첫 그물
├─ /api/* → ALB
│ ↓
│ [(선택) WAF + ALB] ← 두 번째 그물
│ ↓
│ [ECS]
└─ /static/* → S3
- 모든 트래픽은 CloudFront WAF 통과
/api/*만 별도 ALB WAF로 한 번 더 (필요 시)- CloudFront WAF는 us-east-1 글로벌 범위
9. 직접 확인해보기 — CLI
Web ACL 만들기
aws wafv2 create-web-acl \
--name my-acl \
--scope CLOUDFRONT \
--default-action Allow={} \
--visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=my-acl \
--region us-east-1
--scope 가 중요하다.
CLOUDFRONT → CloudFront에 붙일 WAF (반드시 us-east-1)
REGIONAL → ALB · APIGW 등에 붙일 WAF (해당 리전)
Web ACL을 리소스에 붙이기
aws wafv2 associate-web-acl \
--web-acl-arn <acl-arn> \
--resource-arn <alb-arn>
차단된 요청 로그
WAF 로그를 CloudWatch Logs · S3 · Firehose 로 보낼 수 있다.
aws wafv2 put-logging-configuration ...
운영에서는 로그 없이 WAF를 켜지 않는다.
오탐이 났을 때 추적이 안 된다.
10. 코드로는 이렇게 생겼다 — Terraform
CloudFront에 붙일 WAF 한 벌의 모양이다.
resource "aws_wafv2_web_acl" "main" {
provider = aws.us_east_1 # CloudFront WAF는 us-east-1
name = "main-acl"
scope = "CLOUDFRONT"
default_action {
allow {}
}
rule {
name = "AWSManagedRulesCommonRuleSet"
priority = 1
override_action {
none {}
}
statement {
managed_rule_group_statement {
vendor_name = "AWS"
name = "AWSManagedRulesCommonRuleSet"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "common"
sampled_requests_enabled = true
}
}
rule {
name = "RateLimit"
priority = 10
action {
block {}
}
statement {
rate_based_statement {
limit = 2000
aggregate_key_type = "IP"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "rate-limit"
sampled_requests_enabled = true
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "main-acl"
sampled_requests_enabled = true
}
}
이 정도가 처음 켤 때의 적정 출발선이다.
11. 이렇게 쓰면 망한다 — 안티패턴
안티패턴 1. 룰을 추가하자마자 BLOCK 으로 둔다
정상 트래픽이 같이 잡혀 장애가 난다.
새 룰은 COUNT 로 며칠 → 로그 확인 → BLOCK 전환
안티패턴 2. WAF 로그를 안 켠다
차단됐는데 왜 차단됐는지 추적이 안 된다.
WAF는 로그 없이 운영하지 않는다
안티패턴 3. WAF에만 의존하고 애플리케이션 검증을 안 한다
WAF는 그물이지 잠금장치가 아니다.
입력 검증 · 인증 · 권한 검사 모두 애플리케이션에 있어야 한다
안티패턴 4. CloudFront WAF를 서울 리전에서 만들려고 한다
scope = CLOUDFRONT 인데 region = ap-northeast-2 → 실패
CloudFront WAF는 반드시 us-east-1
12. 한 줄로 정리
WAF는 엣지에서 악성 트래픽을 거르는 첫 번째 그물이며,
애플리케이션 검증을 대체하지 않는 추가 계층이다
13. 이 장의 핵심 정리
- WAF는 HTTP 레벨 공격을 엣지에서 거르는 보안 계층이다.
- Web ACL · Rule · Rule Group의 3단 구조다.
- AWS Managed Rules로 시작해 환경에 맞게 보강한다.
- Rate-based Rule로 폭증 트래픽과 무차별 시도를 막는다.
- 새 룰은 COUNT 모드로 검증 후 BLOCK으로 옮긴다.
- WAF는 첫 그물이지 마지막 방어선이 아니다.
- CloudFront WAF는 us-east-1, ALB / APIGW WAF는 해당 리전.